package com.evzgaga.evzrecon.xmlrpc.client;

import com.evzgaga.evzrecon.event.GbxWriterListener;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.XmlRpcRequest;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientException;
import org.apache.xmlrpc.client.XmlRpcStreamTransport;
import org.apache.xmlrpc.common.XmlRpcStreamConfig;
import org.apache.xmlrpc.common.XmlRpcStreamRequestConfig;
import org.apache.xmlrpc.serializer.XmlRpcWriter;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

/**
 *
 * @author Bastien
 */
class XmlRpcRawSocketTransport extends XmlRpcStreamTransport implements GbxWriterListener {

    private GbxRemoteConnection server;
    private static final Logger logger = Logger.getLogger(XmlRpcRawSocketTransport.class.getName());
    private int requestHandle;

    protected XmlRpcRawSocketTransport(XmlRpcClient client) throws IOException {
        super(client);

        XmlRpcRawSocketClientConfig config = (XmlRpcRawSocketClientConfig) client.getConfig();
        server = config.server;
    }

    @Override
    protected void close() throws XmlRpcClientException {
        //Gently ignore the request, we want the socket to be reused!
    }

    @Override
    protected boolean isResponseGzipCompressed(XmlRpcStreamRequestConfig pConfig) {
        return false;
    }

    @Override
    protected InputStream getInputStream() throws XmlRpcException {
        try {
            return server.getServerInputStream();
        } catch (IOException ex) {
            throw new XmlRpcClientException("Could not retrieve an input stream for the socket", ex);
        }
    }

    @Override
    protected void writeRequest(ReqWriter pWriter) throws XmlRpcException, IOException, SAXException {
        pWriter.write(server.getServerOutputStream());
    }

    @Override
    protected ReqWriter newReqWriter(XmlRpcRequest request) throws XmlRpcException, IOException, SAXException {
        return new RawSocketReqWriter(request, this);
    }

    @Override
    protected Object readResponse(XmlRpcStreamRequestConfig pConfig, InputStream pStream) throws XmlRpcException {
        byte[] responseContent = null;
        try {
            responseContent = server.getGbxResponse(requestHandle);
        } catch (InterruptedException ex) {
            throw new XmlRpcException("Could not read server response", ex);
        }

        return (responseContent.length > 0) ? super.readResponse(pConfig, new ByteArrayInputStream(responseContent))
                : "";
    }

    public void onDocumentEnded(String documentContent) {
        requestHandle = server.sendGbxRequest(documentContent);
    }

    private class RawSocketReqWriter implements ReqWriter {

        private final XmlRpcRequest request;
        private final GbxWriterListener transport;

        public RawSocketReqWriter(XmlRpcRequest request, GbxWriterListener transport) {
            this.request = request;
            this.transport = transport;
        }

        public void write(OutputStream pStream) throws XmlRpcException, IOException, SAXException {
            final XmlRpcStreamConfig config = (XmlRpcStreamConfig) request.getConfig();
            ContentHandler h = getClient().getXmlWriterFactory().getXmlWriter(config, pStream);

            if (h instanceof GbxXmlWriter) {
                ((GbxXmlWriter) h).setGbxDocumentListener(transport);
            }

            XmlRpcWriter xw = new XmlRpcWriter(config, h, getClient().getTypeFactory());
            xw.write(request);
        }
    }
}
